﻿using BootyBay.StoreAppMgmtCore.Models;
using BootyBay.StoreAppMgmtCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BootyBay.StoreAppMgmtCore
{
    public class StoreAppMgmtTaskRepository
    {
        public static StoreAppMgmtTaskRepository Instance()
        {
            if (_instance == null)
            {
                _instance = new StoreAppMgmtTaskRepository();
            }
            return _instance;
        }

        /// <summary>
        /// TODO. bad code implementation for the property.
        /// </summary>
        public string ClientUserName { get; set; }

        private static StoreAppMgmtTaskRepository _instance;

        AppMgmtServicesReference.AppMgmtServicesClient appMgmtSvcsClient = new AppMgmtServicesReference.AppMgmtServicesClient();

        
        private StoreAppMgmtTaskRepository()
        {
            cachedTaskListInMemory = new List<StoreAppMgmtTask>(); //store into db in future   
           // storeSvcClient = new StoreServicesRef.StoreServicesClient();
           
        }

       // StoreServicesRef.StoreServicesClient storeSvcClient;
        public List<StoreAppMgmtTask> GetAllAppMgmtTasks(string userName, AppOperationStatus statusType)
        {
            return cachedTaskListInMemory.Where(t=>t.UserName.Equals(userName, StringComparison.InvariantCultureIgnoreCase) && t.OptStatus == statusType).ToList();
        }


        private List<StoreAppMgmtTask> cachedTaskListInMemory;

        

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appVerInfoID"></param>
        /// <param name="optType"></param>
        /// <param name="userName"></param>
        /// <returns>TaskID. Empty if fails</returns>
        public Guid SubmitAppMgmtTask(StoreAppMgmtTask mgmtTask)
        {
            var mgmtTaskInQueue = cachedTaskListInMemory.Where(t => t.AppVerInfoID == mgmtTask.AppVerInfoID && t.UserName == mgmtTask.UserName
                && t.OptType == mgmtTask.OptType
                 && (t.OptStatus == AppOperationStatus.AgentReceived || t.OptStatus == AppOperationStatus.RequestSubmitted)).FirstOrDefault();

            if (mgmtTaskInQueue != null)
                return mgmtTaskInQueue.TaskID;
            else
            {
                mgmtTask.OptStatus = AppOperationStatus.RequestSubmitted;
                mgmtTask.TaskID = Guid.NewGuid();
                cachedTaskListInMemory.Add(mgmtTask);

                return mgmtTask.TaskID;
            }
        }

        public void UpdateTaskStatus(Guid taskID, AppOperationStatus newOptStatus)
        {
            var task = GetTaskStatus(taskID);
            if (task != null)
            {
                task.OptStatus = newOptStatus;
              
            }
        }

        public StoreAppMgmtTask GetTaskStatus(Guid taskID)
        {
            var task = cachedTaskListInMemory.Where(t => t.TaskID == taskID).FirstOrDefault();
            return task;
        }

        /// <summary>
        /// mgmtTask.AppVerInfoID, mgmtTask.UserName, mgmtTask.AppPackageName,mgmtTask.AppPublisherName,mgmtTask.AppVersion
        /// </summary>
        /// <param name="mgmtTask"></param>
        /// <returns></returns>
        public Models.AppLocalStatus GetAppLocalStatus(StoreAppMgmtTask mgmtTask)
        {
            //var appVerInfo = storeSvcClient.GetVersionInfo(appVerInfoID);

            var mgmtTaskInQueue = cachedTaskListInMemory.Where(t => t.AppVerInfoID == mgmtTask.AppVerInfoID && t.UserName == mgmtTask.UserName &&
                (t.OptStatus == AppOperationStatus.AgentReceived || t.OptStatus == AppOperationStatus.RequestSubmitted)).FirstOrDefault();

            if (mgmtTaskInQueue != null)
            {
                return AppLocalStatus.Processing;
            }


            AppMgr appMgr = new AppMgr();
            var pkgFound = appMgr.FindPackage(mgmtTask.AppPackageName, mgmtTask.AppPublisherName);

            if (pkgFound == null)
            {
                return AppLocalStatus.InStore;
            }
            else
            {
                var pkgVer = new System.Version(pkgFound.AppPackageVersion);
                var storeVer = new System.Version(mgmtTask.AppVersion);

                if (storeVer > pkgVer)
                    return AppLocalStatus.OutDated;
                else
                    return AppLocalStatus.Installed;
            }

            //return AppLocalStatus.Unknown;            

        }

        /// <summary>
        /// Install & Update: AppPackageName,AppPublisherName, PackageCertLocationUrl, PackageLocationUrl
        /// Uninstall: AppPackageName,AppPublisherName,
        /// </summary>
        /// <param name="mgmtTask"></param>
        /// <param name="msgNotification"></param>
        public void ProcessAppMgmtTask(StoreAppMgmtTask mgmtTask, Action<string> msgNotification)
        {
           try
            {
                //check all currently installed apps. 
                AppMgr appOperationMgr = new AppMgr();

                appOperationMgr.OnNotificationOutput += (s, e) =>
                {
                    msgNotification(e.EventMessage);
                };

                var existingPkg = appOperationMgr.FindPackage(mgmtTask.AppPackageName, mgmtTask.AppPublisherName);
               
                msgNotification("Task " +mgmtTask.TaskID.ToString()+ " retrieved - " + mgmtTask.AppPackageName + " - " + mgmtTask.OptType.ToString() + " - " + mgmtTask.OptStatus.ToString());

                mgmtTask.OptStatus = AppOperationStatus.AgentReceived;

                bool succeeded = false;
                switch (mgmtTask.OptType)
                {
                    case AppOperationType.Install:
                        {

                            if (existingPkg == null)
                            {
                                appOperationMgr.InstallCert(mgmtTask.PackageCertLocationUrl);
                                succeeded = appOperationMgr.AddPackage(mgmtTask.PackageLocationUrl);

                            }
                            else
                            {
                                //update app
                                appOperationMgr.InstallCert(mgmtTask.PackageCertLocationUrl);
                                succeeded = appOperationMgr.UpdatePackage(mgmtTask.PackageLocationUrl);

                            }

                        } break;

                    case AppOperationType.Update:
                        {

                            if (existingPkg != null)
                            {
                                appOperationMgr.InstallCert(mgmtTask.PackageCertLocationUrl);
                                succeeded = appOperationMgr.UpdatePackage(mgmtTask.PackageLocationUrl);

                            }
                            else
                            {
                                //update app
                                appOperationMgr.InstallCert(mgmtTask.PackageCertLocationUrl);
                                succeeded = appOperationMgr.AddPackage(mgmtTask.PackageLocationUrl);

                            }

                        } break;
                               
                    case AppOperationType.Uninstall:
                        {
                            if (existingPkg != null)
                            {
                                succeeded = appOperationMgr.RemovePackage(existingPkg.AppPackageFullName);
                            }
                            //uninstall directly

                        } break;

                    default: { } break;
                }

                if (succeeded)
                {
                    mgmtTask.OptStatus = Models.AppOperationStatus.Succeeded;

                    AppMgmtServicesReference.AppOperationType svcOptType = AppMgmtServicesReference.AppOperationType.Install;

                    switch (mgmtTask.OptType)
                    {
                        case AppOperationType.Install: svcOptType= AppMgmtServicesReference.AppOperationType.Install;break;
                        case AppOperationType.Uninstall: svcOptType = AppMgmtServicesReference.AppOperationType.Uninstall;break;
                        case AppOperationType.Update : svcOptType = AppMgmtServicesReference.AppOperationType.Update;break;
                        default:break; //no problem for the blank "default" statement. the 'succeeded' flag filters unexpected results.
                    }

                    var submittedRecord =  appMgmtSvcsClient.InsertOptRecord(this.ClientUserName, svcOptType, mgmtTask.AppInfoID);
                    
                    msgNotification("OptRecord submitted at " + submittedRecord.LastUpdateTimeStamp.ToString()); 

                }
                else
                    mgmtTask.OptStatus = Models.AppOperationStatus.Failed;

                msgNotification("Task " + mgmtTask.TaskID.ToString() + " " + mgmtTask.OptStatus.ToString());
            }
            catch (Exception ex)
            {
                mgmtTask.OptStatus = Models.AppOperationStatus.Failed;
                mgmtTask.TaskNote = ex.Message;
                msgNotification("Task " + mgmtTask.TaskID.ToString() + " Failed. " + ex.Message);
                // svcClient.ReportTaskStatus(task.TaskID, StoreServicesRef.AppOperationStatus.Failed, ex.Message);
            }

           

        }

       
    }
 
}
